using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

using NuMetaheuristics;
using System.ComponentModel.Composition;

namespace NuMetaheuristics.Genotypes
{
    /// <summary>
    /// Contains an array (vector) of value elements.
    /// </summary>
    /// <typeparam name="T">The element type</typeparam>
    [DataContract(Name="VectorGenotypeOf{0}", 
        Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    abstract public class VectorGenotype<T>
    {
        [DataMember]
        public Fitness Fitness { get; set; }

        [DataMember]
        public T[] Vector { get; protected set; }

        public VectorGenotype()
        {
            Vector = new T[1];
        }

        public VectorGenotype(int len)
        {
            Vector = new T[len];
        }

        public VectorGenotype(VectorGenotype<T> other)
        {
            initializeFromVector(other.Vector);
        }
        
        public VectorGenotype(T[] vector)
        {
            initializeFromVector(vector);
        }

        private void initializeFromVector(T[] vector)
        {
            Vector = new T[vector.GetLength(0)];
            vector.CopyTo(Vector, 0);
        }
    }

    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    [Export(typeof(IGenotype))]
    public class DoubleVectorGenotype : VectorGenotype<double>, IGenotype
    {
        public DoubleVectorGenotype()
            : base()
        {
        }

        public DoubleVectorGenotype(int len)
            : base(len)
        {
        }

        public DoubleVectorGenotype(DoubleVectorGenotype other)
            : base (other)
        {
        }

        public DoubleVectorGenotype(double[] vector)
            : base (vector)
        {
        }

        public int CompareTo(object obj)
        {
            if (obj.GetType() != this.GetType())
                throw new ArgumentException();
            
            DoubleVectorGenotype other = (DoubleVectorGenotype)obj;

            return Fitness.CompareTo(other.Fitness);
        }

        public object Clone()
        {
            return new DoubleVectorGenotype(this);
        }

        public void CopyTo(object other)
        {
            if (other.GetType() != typeof(DoubleVectorGenotype))
                throw new ArgumentException();

            DoubleVectorGenotype recipient = (DoubleVectorGenotype)other;

            if (recipient.Vector.Length != Vector.Length)
                throw new ArgumentOutOfRangeException();

            Vector.CopyTo(recipient.Vector, 0);
        }
    }

    [Export(typeof(IGenotype))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class IntegerVectorGenotype : VectorGenotype<int>, IGenotype
    {
        public IntegerVectorGenotype()
            : base()
        {
        }

        public IntegerVectorGenotype(int len)
            : base(len)
        {
        }

        public IntegerVectorGenotype(VectorGenotype<int> other)
            : base(other)
        {
        }

        public IntegerVectorGenotype(int[] vector)
            : base(vector)
        {
        }

        public int CompareTo(object obj)
        {
            if (obj.GetType() != this.GetType())
                throw new ArgumentException();
            
            IntegerVectorGenotype other = (IntegerVectorGenotype)obj;

            return Fitness.CompareTo(other.Fitness);
        }

        public object Clone()
        {
            return new IntegerVectorGenotype(this);
        }

        public void CopyTo(object other)
        {
            if (other.GetType() != typeof(IntegerVectorGenotype))
                throw new ArgumentException();

            IntegerVectorGenotype recipient = (IntegerVectorGenotype)other;

            if (recipient.Vector.Length != Vector.Length)
                throw new ArgumentOutOfRangeException();

            Vector.CopyTo(recipient.Vector, 0);
        }
    }

    [Export(typeof(IGenotype))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class BooleanVectorGenotype : VectorGenotype<bool>, IGenotype
    {
        public BooleanVectorGenotype()
            : base()
        {
        }

        public BooleanVectorGenotype(int len)
            : base(len)
        {
        }

        public BooleanVectorGenotype(VectorGenotype<bool> other)
            : base(other)
        {
        }

        public BooleanVectorGenotype(bool[] vector)
            : base(vector)
        {
        }

        public int CompareTo(object obj)
        {
            if (obj.GetType() != this.GetType())
                throw new ArgumentException();
            
            BooleanVectorGenotype other = (BooleanVectorGenotype)obj;

            return Fitness.CompareTo(other.Fitness);
        }
        
        public object Clone()
        {
            return new BooleanVectorGenotype(this);
        }

        public void CopyTo(object other)
        {
            if (other.GetType() != typeof(BooleanVectorGenotype))
                throw new ArgumentException();

            BooleanVectorGenotype recipient = (BooleanVectorGenotype)other;

            if (recipient.Vector.Length != Vector.Length)
                throw new ArgumentOutOfRangeException();

            Vector.CopyTo(recipient.Vector, 0);
        }
    }
}